#include "vtor_flash_eeprom.h"

#ifdef __VTOR_FLASH_EEPROM__


uint32_t VtorFlashEeprom_GetNewDataAddr(
	VtorFlashEeprom* eeprom, uint32_t curAddr)
{
	uint32_t nextAddr = curAddr;
	// 如果未找到，认为未写过eeprom，指向开头
	if(0x00000000 == nextAddr)
	{
		nextAddr = eeprom->flashStartAddress;
	}
	else
	{
		// 否则指向下一个eeprom偏移
		nextAddr += eeprom->eepromSize;
	}
	if(nextAddr >= eeprom->flashStartAddress
		+ eeprom->flashPageSize * eeprom->flashPageCnt)
	{
		nextAddr = eeprom->flashStartAddress; // 越界了，修正到开始地址
	}
	// 必须处于页边界才执行擦除操作
	if(0 == nextAddr % eeprom->flashPageSize)
	{
		// 如果发现下一个地址有有效数据，那么执行擦除
		if(VtorFlash_CheckValid(nextAddr, eeprom->flashPageSize))
		{
			VtorFlash_Erase(nextAddr);
		}
	}
	return nextAddr;
}

// 寻找最新可用的数据地址
uint32_t VtorFlashEeprom_GetCurDataAddr(VtorFlashEeprom* eeprom)
{
	// 把最大idx的地址存储在curAddr内
	uint32_t maxEepromAddr = 0x00000000;
	uint32_t maxEepromIdx = 0;
	
	// 根据flash页偏移，寻找基础地址
	for(uint32_t flashIdx = 0; flashIdx < eeprom->flashPageCnt; flashIdx++)
	{
		uint32_t flashBaseAddr = eeprom->flashStartAddress
			+ flashIdx * eeprom->flashPageSize;
		for(uint32_t eepromIdx = 0;
			eepromIdx < eeprom->flashPageSize / eeprom->eepromSize; eepromIdx++)
		{
			uint32_t flashAddr = flashBaseAddr + eepromIdx * eeprom->eepromSize;
			// 从前往后，发现全f，说明当前flashpage没数据，不再需要扫描
			VtorFlashEepromData* eepromData = (VtorFlashEepromData*)flashAddr;

			// 如果两者不是互为反码，认为校验失败
			if(eepromData->idx != -eepromData->revIdx)
			{
				break;
			}
			if(0x00000000 == maxEepromAddr)
			{
				maxEepromAddr = flashAddr;
				maxEepromIdx = eepromData->idx;
			}
			else
			{
				uint32_t eepromDataOverflow = 0;
				uint32_t maxOverflow = 0;
				if(eepromData->idx < VTOR_EEPROM_LITTLE
					&& maxEepromIdx > VTOR_EEPROM_BIG)
				{
					eepromDataOverflow = VTOR_EEPROM_MAX;
				}
				if(eepromData->idx > VTOR_EEPROM_BIG
					&& maxEepromIdx < VTOR_EEPROM_LITTLE)
				{
					maxOverflow = VTOR_EEPROM_MAX;
				}
				// 如果id相同，也以后面的为最新，所以允许相等情况
				if(eepromData->idx + eepromDataOverflow
					>= maxEepromIdx + maxOverflow)
				{
					maxEepromAddr = flashAddr;
					maxEepromIdx = eepromData->idx;
				}
			}
			//VtorDebugChanPrintf("max[%x]=%d\r\n", maxEepromAddr, maxEepromIdx);
		}
	}
	return maxEepromAddr;
}

// eeprom只提供read与write方法
uint32_t VtorFlashEeprom_Read(
	VtorFlashEeprom* eeprom, uint32_t* data, uint32_t len)
{
	uint32_t readAddr = VtorFlashEeprom_GetCurDataAddr(eeprom);
	
	uint32_t retAddr = VtorFlash_Read(readAddr, data, len);
	
	//VtorDebugChanPrintf("VtorFlashEeprom_Read [%x] = %d, ret %x\r\n",
	//			readAddr, eepromData->idx, retAddr);
	return retAddr;	
}

uint32_t VtorFlashEeprom_Write(
	VtorFlashEeprom* eeprom, uint32_t* data, uint32_t len)
{
	VtorFlashEepromData* eepromData = (VtorFlashEepromData*)data;
	// 写之前保证idx变化，同时防止id溢出
	eepromData->idx++;
	eepromData->idx %= VTOR_EEPROM_MAX;
	// 设置反码
	eepromData->revIdx = -eepromData->idx;
	
	uint32_t curAddr = VtorFlashEeprom_GetCurDataAddr(eeprom);
	uint32_t newAddr = VtorFlashEeprom_GetNewDataAddr(eeprom, curAddr);
	
	uint32_t retAddr = VtorFlash_Write(newAddr, data, len);
	
	//VtorDebugChanPrintf("VtorFlashEeprom_Write [%x->%x] = %d, ret %x\r\n",
	//			curAddr, newAddr, eepromData->idx, retAddr);
	return retAddr;
}


uint32_t VtorFlashEeprom_Erase(VtorFlashEeprom* eeprom)
{
	for(uint32_t flashIdx = 0; flashIdx < eeprom->flashPageCnt; flashIdx++)
	{
		uint32_t flashBaseAddr = eeprom->flashStartAddress
			+ flashIdx * eeprom->flashPageSize;
		VtorFlash_Erase(flashBaseAddr);
	}
	return eeprom->flashStartAddress;
}

void VtorFlashEeprom_Scan(VtorFlashEeprom* eeprom)
{
	// 根据flash页偏移，寻找基础地址
	for(uint32_t flashIdx = 0; flashIdx < eeprom->flashPageCnt; flashIdx++)
	{
		uint32_t flashBaseAddr = eeprom->flashStartAddress
			+ flashIdx * eeprom->flashPageSize;
		for(uint32_t eepromIdx = 0;
			eepromIdx < eeprom->flashPageSize / eeprom->eepromSize; eepromIdx++)
		{
			uint32_t flashAddr = flashBaseAddr + eepromIdx * eeprom->eepromSize;
			VtorFlashEepromData* eepromData = (VtorFlashEepromData*)flashAddr;
			VtorDebugChanPrintf("[%x] = %x(%d), %d\r\n", flashAddr,
				eepromData->idx, eepromData->idx, eepromData->revIdx);
		}
	}
}

uint32_t VtorFlashEeprom_Test(VtorFlashEeprom* eeprom)
{
	uint32_t wData[5] = {8800};
	uint32_t rData[5] = {8700};
	

	// 读出，修改再写入，保证测试顺利运行
	VtorFlashEeprom_Read(eeprom, wData, sizeof(wData));
	uint32_t writeAddr = VtorFlashEeprom_Write(eeprom, wData, sizeof(wData));

	// 再读出进行对比，确保更新没问题
	uint32_t readAddr = VtorFlashEeprom_Read(eeprom, rData, sizeof(rData));
	
	
	VtorFlashEepromData* wEepromData = (VtorFlashEepromData*)wData;
	VtorFlashEepromData* rEepromData = (VtorFlashEepromData*)rData;
	
	if(writeAddr != readAddr || wEepromData->idx != rEepromData->idx)
	{
		VtorDebugChanPrintf("write %x %x\r\n", writeAddr, wEepromData->idx);
		VtorDebugChanPrintf("read  %x %x\r\n", readAddr, rEepromData->idx);
	}
	return readAddr;
}

#endif // __VTOR_FLASH_EEPROM__
